package tools

import (
	"database/sql"
	"fmt"
	"github.com/go-xorm/xorm"
	"io/ioutil"
	"log"
	"os"
)

/**
 * @author ljfirst
 * @version V1.0
 * @date 2023/9/11 17:31
 * @author-Email ljfirst@mail.ustc.edu.cn
 * @blogURL https://blog.csdn.net/ljfirst
 * @description
 * DB 2 Struct
 * Struct 2 DB
 **/

var (
	DBName               = "algo_db"
	Table                = "all_in"
	DataSourceNameLocal  = fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8", "root", "12345678", "localhost", 3306, "algo_db")
	DataSourceNameRemote = fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8", "mysql_user", "pwdMysql*2023", "118.195.234.62", 3306, "algo_db")
	packageName          = "db_entity"
	Path                 = "/Users/liujun/workspace/code/algo/algo-go-protal/integration/db/" + packageName
	fieldConn            *sql.Rows
	rows                 *sql.Rows
)

// 根据DB生成Struct
func DB2Struct() {
	// 连接mysql
	db, err := sql.Open("mysql", DataSourceNameLocal)
	if err != nil {
		fmt.Println("连接数据库失败,失败原因是:", err)
		return
	}

	//获取所有表
	var sqlStr = "select table_name from information_schema.tables where table_schema=?"
	// 指定生成某表
	if Table != "all_in" {
		sqlStr = fmt.Sprintf(" select table_name from  information_schema.columns where table_schema =? and table_name = '%s' ", Table)
	}
	rows, err = db.Query(sqlStr, DBName)
	if err != nil {
		fmt.Println("查询数据库失败,失败原因是:", err)
		return
	}
	defer func() {
		if rows != nil { //防止过多连接没有释放 导致内存泄露
			rows.Close()
		}
	}()
	tableStrut := DbTable{}

	defer func() {
		if fieldConn != nil {
			_ = fieldConn.Close()
		}
	}()

	for rows.Next() {
		err = rows.Scan(&tableStrut.Name)
		if err != nil {
			fmt.Printf("生成表失败,失败原因是:err:%v", err)
			return
		}
		//获取单个表所有字段
		sqlStr = fmt.Sprintf("select column_name columnName, data_type dataType, column_comment columnComment, "+
			"column_key columnKey, column_type columnType, extra "+
			"from information_schema.columns where table_name = '%s' and table_schema =(select database()) order by ordinal_position ", tableStrut.Name)
		fieldConn, err = db.Query(sqlStr)
		if err != nil {
			fmt.Println("mysql 获取单个表所有字段 err:", err)
		}

		// ----- 拼接生成的struct  start--------
		structStr := fmt.Sprintf("type %s struct { \n", CapFirstLetter(tableStrut.Name))
		column := Column{}
		TimeFlag := false
		for fieldConn.Next() {
			err = fieldConn.Scan(&column.ColumnName, &column.DataType, &column.ColumnComment,
				&column.ColumnKey, &column.ColumnType, &column.Extra)
			if err != nil {
				fmt.Printf("获取失败,失败原因是:err:%v", err)
				return
			}
			structStr += "    " + CapFirstLetter(column.ColumnName)
			switch column.DataType {
			case "int", "tinyint":
				structStr += " int"
			case "bigint":
				structStr += " int64"
			case "timestamp", "date", "datetime":
				structStr += " time.Time "
				TimeFlag = true
			case "decimal":
				structStr += " float64"
			default:
				structStr += " string"
			}

			switch column.Extra {
			case "auto_increment":
				structStr += fmt.Sprintf("`json:\"%s\" gorm:\"not null comment('%s') INT(11)\" xorm:\"not null comment('%s') INT(11)\" ` \n",
					column.ColumnName, column.ColumnComment, column.ColumnComment)
			default:
				structStr += fmt.Sprintf("`json:\"%s\" gorm:\"comment('%s') %s \"  xorm:\"comment('%s') %s \" ` \n",
					column.ColumnName, column.ColumnComment, column.ColumnType, column.ColumnComment, column.ColumnType)
			}
		}
		structStr += "}"
		modelHead := "package " + packageName + " \n\n"

		if TimeFlag {
			modelHead += "import \"time\" \n\n"
		}
		// ----- 拼接生成的struct end --------
		if PathProcessing(Path) {
			fmt.Println("路径不匹配")
			return
		}
		//导出文件并创建文件夹
		body := modelHead + structStr
		filename := fmt.Sprintf("%s/%s.go", Path, tableStrut.Name)
		error2 := os.MkdirAll(Path, os.ModePerm)
		if error2 != nil {
			fmt.Println("创建文件夹 err:", error2)
		}
		err4 := ioutil.WriteFile(filename, []byte(body), 0666)
		if err4 != nil {
			fmt.Println("写入文件错误:", err4)
		}
	}
	fmt.Println("Successful")
}

// 根据Struct生成DB
func Struct2DB(tableNames ...interface{}) {
	x, err := xorm.NewEngine("mysql", DataSourceNameLocal)
	if err != nil {
		log.Fatalf("conn database error: %v\n", err)
	}
	// 不传入指定 数据库表名， 默认读取 integration/db/db_entity/ 下的全部struct进行同步
	if len(tableNames) == 0 {
		GetPathStruct(GetDBFilePath())
	}
	// 同步指定数据库结构体
	for _, tableName := range tableNames {
		err1 := x.Sync2(tableName)
		if err1 != nil {
			log.Fatalf("Fail to sync database: %v\n", err1)
		}
	}
}

// DbTable 表类型
type DbTable struct {
	Name string `json:"name"`
}

// Column 数据字段类型
type Column struct {
	ColumnName    string `json:"column_name"`
	DataType      string `json:"data_type"`
	ColumnComment string `json:"column_comment"`
	ColumnKey     string `json:"column_key"`
	Extra         string `json:"extra"`
	ColumnType    string `json:"column_type"`
}
